/******************************************************************************* * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Robert M. Fuhrer (rfuhrer@watson.ibm.com), IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets; import java.util.Iterator; import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.ArrayType; import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType; import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.TTypes; public class SubTypesSet extends TypeSet { /** * The set of "base types" defining the upper bounds of this set. */ private TypeSet fUpperBounds; SubTypesSet(TypeSet superTypes) { super(superTypes.getTypeSetEnvironment()); fUpperBounds= superTypes; } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#isUniverse() */ public boolean isUniverse() { return fUpperBounds.isUniverse() || fUpperBounds.contains(getJavaLangObject()); } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#makeClone() */ public TypeSet makeClone() { return this; //new SubTypesSet(fUpperBounds.makeClone()); } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object o) { if (o instanceof SubTypesSet) { SubTypesSet other= (SubTypesSet) o; return other.fUpperBounds.equals(fUpperBounds); // } else if (o instanceof TypeSet) { // TypeSet other= (TypeSet) o; // if (other.isUniverse() && isUniverse()) // return true; // return enumerate().equals(other.enumerate()); } else return false; } public int hashCode() { return fUpperBounds.hashCode(); } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#intersectedWith(org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.EnumeratedTypeSet) */ protected TypeSet specialCasesIntersectedWith(TypeSet s2) { if (fUpperBounds.equals(s2)) return s2; // xsect(subTypes(A),A) = A if (s2 instanceof SubTypesSet) { SubTypesSet st2= (SubTypesSet) s2; if (fUpperBounds.isSingleton() && st2.fUpperBounds.isSingleton()) { TType t1= this.fUpperBounds.anyMember(); TType t2= st2.fUpperBounds.anyMember(); if (TTypes.canAssignTo(t2, t1)) return new SubTypesSet(st2.fUpperBounds); } else if (fUpperBounds instanceof SubTypesSet) { // xsect(subTypes(superTypes(A)), subTypes(A)) = subTypes(A) SubTypesSet myUpperSubTypes= (SubTypesSet) fUpperBounds; if (myUpperSubTypes.lowerBound().equals(st2.lowerBound())) return st2; } } if (s2 instanceof SubTypesOfSingleton) { SubTypesOfSingleton st2= (SubTypesOfSingleton) s2; if (fUpperBounds.isSingleton()) { TType t1= this.fUpperBounds.anyMember(); TType t2= st2.uniqueUpperBound(); if (TTypes.canAssignTo(t2, t1)) return getTypeSetEnvironment().createSubTypesOfSingleton(t2); } else if (fUpperBounds instanceof SubTypesOfSingleton) { // xsect(subTypes(superTypes(A)), subTypes(A)) = subTypes(A) SubTypesOfSingleton myUpperSubTypes= (SubTypesOfSingleton) fUpperBounds; if (myUpperSubTypes.uniqueLowerBound().equals(st2.uniqueLowerBound())) return st2; } } if (s2 instanceof SuperTypesSet) { SuperTypesSet st2= (SuperTypesSet) s2; if (fUpperBounds.equals(st2.lowerBound())) return fUpperBounds; if (fUpperBounds instanceof TypeSetIntersection) { // (intersect (subTypes (intersect (superTypes A) B)) // (superTypes A)) => // (intersect (superTypes A) (subTypes B)) TypeSetIntersection lbXSect= (TypeSetIntersection) fUpperBounds; TypeSet xsectLeft= lbXSect.getLHS(); TypeSet xsectRight= lbXSect.getRHS(); if (xsectLeft.equals(st2.lowerBound())) return new TypeSetIntersection(s2, new SubTypesSet(xsectRight)); } } return null; } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#subTypes() */ public TypeSet subTypes() { return this; // makeClone(); } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#isEmpty() */ public boolean isEmpty() { return fUpperBounds.isEmpty(); } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#contains(TType) */ public boolean contains(TType t) { if (fEnumCache != null) return fEnumCache.contains(t); if (fUpperBounds.contains(t)) return true; // Find the "upper frontier", i.e. the upper bound, and see whether // the given type is a subtype of any of those. Iterator ubIter= fUpperBounds.upperBound().iterator(); for(; ubIter.hasNext(); ) { TType ub= (TType) ubIter.next(); if (TTypes.canAssignTo(t, ub)) return true; } return false; } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#containsAll(org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.EnumeratedTypeSet) */ public boolean containsAll(TypeSet s) { if (fEnumCache != null) return fEnumCache.containsAll(s); if (fUpperBounds.containsAll(s)) return true; // Make sure all elements of s are contained in this set for(Iterator sIter= s.iterator(); sIter.hasNext(); ) { TType t= (TType) sIter.next(); boolean found= false; // Scan the "upper frontier", i.e. the upper bound set, and see whether // 't' is a subtype of any of those. for(Iterator ubIter= fUpperBounds /*.upperBound() */.iterator(); ubIter.hasNext(); ) { TType ub= (TType) ubIter.next(); if (TTypes.canAssignTo(t, ub)) { found= true; break; } } if (!found) return false; } return true; } /** * Returns the element type of the given TType, if an array type, or the * given TType itself, otherwise. * * @param t a type * @return the element type */ private TType getElementTypeOf(TType t) { if (t instanceof ArrayType) return ((ArrayType) t).getElementType(); return t; } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#isSingleton() */ public boolean isSingleton() { if (!fUpperBounds.isSingleton()) return false; TType t= fUpperBounds.anyMember(); return getElementTypeOf(t).getSubTypes().length == 0; } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#anyMember() */ public TType anyMember() { return fUpperBounds.anyMember(); } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#upperBound() */ public TypeSet upperBound() { return fUpperBounds; // perhaps should be unmodifiable? } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#lowerBound() */ public TypeSet lowerBound() { return enumerate().lowerBound(); } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#iterator() */ public Iterator iterator() { return enumerate().iterator(); } /* (non-Javadoc) * @see java.lang.Object#toString() */ public String toString() { return "<" + fID + ": subTypes(" + fUpperBounds + ")>"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#hasUniqueLowerBound() */ public boolean hasUniqueLowerBound() { return false; } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#hasUniqueUpperBound() */ public boolean hasUniqueUpperBound() { return fUpperBounds.isSingleton(); } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#uniqueLowerBound() */ public TType uniqueLowerBound() { return null; } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#uniqueUpperBound() */ public TType uniqueUpperBound() { return fUpperBounds.isSingleton() ? fUpperBounds.anyMember() : null; } private EnumeratedTypeSet fEnumCache= null; /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#enumerate() */ public EnumeratedTypeSet enumerate() { if (fEnumCache == null) { fEnumCache= new EnumeratedTypeSet(getTypeSetEnvironment()); for(Iterator iter= fUpperBounds.iterator(); iter.hasNext(); ) { TType ub= (TType) iter.next(); if (ub instanceof ArrayType) { ArrayType at= (ArrayType) ub; int numDims= at.getDimensions(); for(Iterator elemSubIter=TTypes.getAllSubTypesIterator(at.getElementType()); elemSubIter.hasNext(); ) fEnumCache.add(TTypes.createArrayType((TType) elemSubIter.next(), numDims)); } else { for (Iterator iterator= TTypes.getAllSubTypesIterator(ub); iterator.hasNext();) { fEnumCache.fMembers.add(iterator.next()); } } fEnumCache.add(ub); } // fEnumCache.initComplete(); } return fEnumCache; } }